package br.pucrs.prototipoonline.xml;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import br.pucrs.prototipoonline.json.ElementoJS;
import br.pucrs.prototipoonline.json.ProjetoJS;
import br.pucrs.prototipoonline.json.TelaJS;
import br.pucrs.prototipoonline.xml.modelos.XMIModelos;


/**
 * 
 * @author Ricardo Luckei
 * @author Gelson Gentil
 *
 */
public class XMIHelper {
	
	public static final String INITIAL_STATE_ID = "-64--88-100--51--28cc5288:11500e15100:-8000:000000000000079E";
	public static final String FINAL_STATE_ID = "-64--88-100--51--28cc5288:11500e15100:-8000:000000000000079F";
	
	private ArrayList<ActionState> actionsState;
	private ArrayList<Transition> transitions;
	
	public XMIHelper() {
		actionsState = new ArrayList<ActionState>();
		transitions = new ArrayList<Transition>();
	}
	
	public void adicionarActionState(ActionState actionState) {
		this.actionsState.add(actionState);
	}
	
	public void adicionarTransition(Transition transition) {
		this.transitions.add(transition);
	}	
	
	
	private String montaXML(ProjetoJS projeto) {
		String content = null;
		String initialOutgoing = null;
		StringBuffer finalIncoming = new StringBuffer();
		StringBuffer buffActionStates = new StringBuffer();
		StringBuffer buffTransitions = new StringBuffer();
		
		//monta o initial
		String initialId = null;
		for(Transition trans : transitions) {
			if(INITIAL_STATE_ID.equals(trans.getSourceId())) {
				initialId = trans.getId();
				break;
			}
		}
		initialOutgoing = XMIModelos.getModeloTransition();
		initialOutgoing = substituiChave(initialOutgoing, "@ID@", initialId);
		
		//monta o final
		for(Transition trans : transitions) {
			if(FINAL_STATE_ID.equals(trans.getTargetId())) {
				String strFinalIncoming = XMIModelos.getModeloTransition();
				strFinalIncoming = substituiChave(strFinalIncoming, "@ID@", trans.getId());
				finalIncoming.append(strFinalIncoming).append("\n");
			}
		}
		
		
		//monta os actionstate com os outgoing e incoming
		for(ActionState actionState : actionsState) {
			StringBuffer incomingTransitions = new StringBuffer();
			StringBuffer outgoingTransitions = new StringBuffer();
			
			String strActionState = XMIModelos.getModeloActionState();
			
			strActionState = substituiChave(strActionState, "@ACTIONSTATE_ID@", actionState.getId());
			strActionState = substituiChave(strActionState, "@TITULO@", actionState.getTitulo());
			while(strActionState.indexOf("@TAG_XMI_ID@")!=-1) {
				strActionState = strActionState.replaceFirst("@TAG_XMI_ID@", generateIDTags());
			}

			//cria as transitions de incoming
			for(String id : actionState.getIncomingTransitions()) {
				String transition = XMIModelos.getModeloTransition();
				transition = substituiChave(transition, "@ID@", id);
				incomingTransitions.append(transition).append("\n");
			}
			//cria as transitions de outgoing
			for(String id : actionState.getOutgoingTransitions()) {
				String transition = XMIModelos.getModeloTransition();
				transition = substituiChave(transition, "@ID@", id);
				outgoingTransitions.append(transition).append("\n");
			}
			
			strActionState = substituiChave(strActionState, "@INCOMING_TRANSITIONS@", incomingTransitions.toString());
			strActionState = substituiChave(strActionState, "@OUTGOING_TRANSITIONS@", outgoingTransitions.toString());
			
			//coloca no buffer
			buffActionStates.append(strActionState).append("\n");
		}
		
		
		//monta os transitions
		for(Transition trans : transitions) {
			String transition = XMIModelos.getModeloTransitions();
			transition = substituiChave(transition, "@TRANSITION_ID@", trans.getId());
			transition = substituiChave(transition, "@SOURCE_ID@", trans.getSourceId());
			transition = substituiChave(transition, "@TARGET_ID@", trans.getTargetId());
			
			buffTransitions.append(transition).append("\n");
		}
		
		//monta o principal
		content = XMIModelos.getModeloContent();
		content = substituiChave(content, "@TITULO_PROJETO@", projeto.getNome());
		content = substituiChave(content, "@INITIAL_STATE_OUTGOING@", initialOutgoing);
		content = substituiChave(content, "@FINAL_STATE_INCOMING@", finalIncoming.toString());
		
		content = substituiChave(content, "@ACTION_STATE@", buffActionStates.toString());
		content = substituiChave(content, "@TRANSITIONS@", buffTransitions.toString());
		
		return content;
	}
	
	private String  substituiChave(String str, String key, String valor) {
		return str.replaceAll(key, valor);
	}
	
	public String processaProjeto(ProjetoJS projeto, int telaInicialId) {
		
		//hash para armazenar a chave {NomeTela}{ID}
		Map<String,ActionState> map = new HashMap<String,ActionState>();

		//cria os ActionState com os IDs
		for(TelaJS tela : projeto.getTelas()) {
			String idActionState = generateActionStateID();
			ActionState actionState = new ActionState(idActionState, tela.getNome());
			
			this.adicionarActionState(actionState);
			map.put(tela.getNome(), actionState);
		}
		
		//cria as transitions
		for(TelaJS tela : projeto.getTelas()) {
			ActionState origem = map.get(tela.getNome());
			
			//linka o Inicio com a tela inicial
			if(tela.getId()==telaInicialId) {
				String transitionID = generateTransitionID();
				ActionState telaInicial = map.get(tela.getNome());
				Transition trans = new Transition(transitionID, INITIAL_STATE_ID, telaInicial.getId());
				adicionarTransition(trans);
				
				telaInicial.addIncomingTransition(transitionID);
			}
			
			//linka todas telas com o final
			String transitionFinalID = generateTransitionID();
			adicionarTransition(new Transition(transitionFinalID, origem.getId(), FINAL_STATE_ID));

			
			//cria as transitions entre as telas
			for(ElementoJS elemento : tela.getElementos()) {
				if(StringUtils.isNotEmpty(elemento.getLink())) {
					ActionState destino = map.get(elemento.getLink());
					
					String transitionID = generateTransitionID();
					Transition trans = new Transition(transitionID, origem.getId(), destino.getId());
					adicionarTransition(trans);
					
					origem.addIncomingTransition(transitionID);
					destino.addOutgoingTransition(transitionID);
				}
			}
		}
		
		return montaXML(projeto);
	}

	
	
	//gerador de id pros taggedValue
	private long tagsIdCont=0;
	private String generateIDTags() {
		String id = "-64--88-100--51--28cc5288:11500e15100:-8000:00000000000A";
		DecimalFormat fmt = new DecimalFormat("0000");
		tagsIdCont++;
		return id+fmt.format(tagsIdCont);
	}
	
	//gerador de id pros actionstate
	private long actionStateCont=0;
	private String generateActionStateID() {
		String id = "-64--88-100--92--2d401dea:115295f58cc:-8000:000000000000";
		DecimalFormat fmt = new DecimalFormat("0000");
		actionStateCont++;
		return id+fmt.format(actionStateCont);
	}
	
	
	//gerador de ids pros transitions
	private long transitionCont=0;
	private String generateTransitionID() {
		String id = "-64--88-100--51--28cc5288:11500e15100:-8000:000000000000";
		DecimalFormat fmt = new DecimalFormat("0000");
		transitionCont++;
		return id+fmt.format(transitionCont);
	}
}
